package com.ux.control
{
	import com.ux.data.VideoData;
	import com.ux.event.VideoProgressEvent;
	import com.ux.event.VideoStatusEvent;
	import com.ux.manager.StageManager;
	import com.ux.util.MathUtil;
	
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.events.NetStatusEvent;
	import flash.events.StatusEvent;
	import flash.media.SoundTransform;
	import flash.media.Video;
	import flash.net.NetConnection;
	import flash.net.NetStream;
	
	
	/**
	 * @author winnie
	 */	
	public class VideoPlayer extends Sprite
	{
		
		public var ns : NetStream;
		public var nc : NetConnection;
		public var vid : Video;
		
		protected var url:String;
		protected var customClient : Object;
		protected var _bufferTime : int = -1;
		protected var _duration : Number;
		protected var _width : Number = -1;
		protected var _height : Number = -1;
		protected var _soundTrans : SoundTransform;
		protected var _isMute : Boolean = false;
		protected var _status : String = "STOP_VIDEO";
		protected var _volume : Number = 1;
		
		
		public function VideoPlayer( _url : String )
		{
			super();
			
			this.url = _url;
			this.makeVideoConnection();
			this._soundTrans = new SoundTransform( 1,0 );
		}
		
		
		//------------------------ video 최초 만드는 작업, 기타 비디오 관련 이벤트 핸들러 ------------------//
		protected function makeVideoConnection():void
		{
			this.nc					= new NetConnection();
			nc.connect( null );
			
			this.ns					= new NetStream( nc );
			this.customClient		= new Object();
			customClient.onMetaData = metaDataHandler;
			this.ns.addEventListener(IOErrorEvent.IO_ERROR, onIOErrorEvent );
			
			ns.client				= customClient;
			ns.bufferTime			= bufferTime;
			
			ns.addEventListener(NetStatusEvent.NET_STATUS, statusHandler);
			this.addEventListener(Event.ENTER_FRAME, onLoadEnter );
			
			this.vid				= new Video();
			
			this.vid.attachNetStream( ns );
			this.addChild( vid );
		}
		
		
		protected function onLoadEnter( e:Event ):void
		{
//			trace( ns.bytesTotal+ " 중 현재 로딩 상태 : " + ns.bytesLoaded );
//			trace( "현재 버퍼의 길이는 : " + ns.bufferLength );
			
			if( ns.bytesLoaded != ns.bytesTotal )
			{
				var per : Number = ns.bytesLoaded/ns.bytesTotal;
				dispatchEvent( new VideoProgressEvent( VideoProgressEvent.VIDEO_LOADING, per ) );
			}
			else
			{
				dispatchEvent( new VideoProgressEvent( VideoProgressEvent.VIDEO_LOAD_COMPLETE, 1 ) );
				removeEventListener( Event.ENTER_FRAME, onLoadEnter );
			}
		}
		
		
		protected function onIOErrorEvent( e:IOErrorEvent ):void
		{
			throw new Error(" AVideo onIOErrorEvent : 로드 IO Error " );
		}
		
		// video 상태 이벤트 핸들러
		protected function statusHandler(e:NetStatusEvent):void
		{
			trace(" ==> AVideo statusHandler : " + e.info.code );
			
			// 버퍼링 채워졌으니 시작.
			if( e.info.code == "NetStream.Buffer.Full" )
			{
				dispatchEvent( new VideoStatusEvent( VideoStatusEvent.VIDEO_BUFFER_PLAY ) );
			}
			// 넷스트림 끝남.
			else if( e.info.code == "NetStream.Play.Stop" )
			{
				this.stopVideo();
				dispatchEvent( new VideoStatusEvent( VideoStatusEvent.VIDEO_STOP ) );
			}
			// 버퍼링 비워짐 pause 또는 버퍼링 끝나서 없음. || 최초 넷스트림 시작시..
			else if( e.info.code == "NetStream.Buffer.Empty" || e.info.code == "NetStream.Play.Start" )
			{
				// 버퍼링 비워져버렸으므로, 버퍼타임 리셋팅.
				ns.bufferTime = _bufferTime;
				dispatchEvent( new VideoStatusEvent( VideoStatusEvent.VIDEO_BUFFER_STOP ) );
			}
		}
		
		// 비디오 메타데이타 핸들러
		protected function metaDataHandler(infoObject:Object):void
		{
			this._duration			= Number( infoObject.duration );
			this.ns.bufferTime		= Number( infoObject.duration );
		}
		
		// 비디오 연결 체크
		protected function connectionCheck():Boolean
		{
			if( !nc || !ns )
			{
				trace(" ==> AVideoConnetor play : 연결된 커넥션이 없습니다 ");
				return false;
			}
			
			else return true;
		}
		
		
		// 얼마나 봤는지 체크함.
		protected function onStatusEnter( e:Event ):void
		{
			if( connectionCheck() )
			{
				var per : Number = ns.time / this._duration;
				dispatchEvent( new VideoStatusEvent( VideoStatusEvent.VIDEO_TIME_CHANGE, "", 1, per ) );
			}
		}
		//------------------------ video 최초 만드는 작업, 기타 비디오 관련 이벤트 핸들러 끝------------------//
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		//-----------------------------------------------------------------------------------
		//
		// controller api
		//
		//-----------------------------------------------------------------------------------
		
		/** 비디오 시작( 처음부터 ) **/
		public function playVideo():void
		{
			if( connectionCheck() == false ) return;
			_status = VideoData.STATUS_PLAY;
			
			if( this.ns.bufferTime != this.bufferTime ) this.ns.bufferTime = this.bufferTime;
			this.ns.play(url);
			this.addEventListener(Event.ENTER_FRAME, onStatusEnter );
			dispatchEvent( new VideoStatusEvent( VideoStatusEvent.VIDEO_PLAY, url, volume ) );
			dispatchEvent( new VideoStatusEvent( VideoStatusEvent.VIDEO_BUFFER_STOP ) );
		}
		
		/** 비디오 멈춤( 처음으로 되돌림 ) **/
		public function stopVideo():void
		{
			if( connectionCheck() == false ) return;
			_status = VideoData.STATUS_STOP;
			this.ns.seek( 0 );
			this.ns.pause();
			this.removeEventListener(Event.ENTER_FRAME, onStatusEnter );
			dispatchEvent( new VideoStatusEvent( VideoStatusEvent.VIDEO_STOP, url, volume ) );
		}
		
		/** 비디오 멈춤( 제자리 ) **/
		public function pauseVideo():void
		{
			if( connectionCheck() == false ) return;
			_status = VideoData.STATUS_PAUSE;
			this.ns.pause();
			this.removeEventListener(Event.ENTER_FRAME, onStatusEnter );
			dispatchEvent( new VideoStatusEvent( VideoStatusEvent.VIDEO_PAUSE, url, volume ) );
		}
		
		/** 비디오 재시작( 현재 위치에서 ) **/
		public function resumeVideo():void
		{
			if( connectionCheck() == false ) return;
			_status = VideoData.STATUS_PLAY;
			this.ns.resume();
			this.addEventListener(Event.ENTER_FRAME, onStatusEnter );
			dispatchEvent( new VideoStatusEvent( VideoStatusEvent.VIDEO_RESUME, url, volume ) );
		}
		
		/** 비디오 커넥션 종료 **/
		public function closeVideo():void
		{
			if( connectionCheck() == false ) return;
			
			_status = VideoData.STATUS_STOP;
			
			this.ns.pause();
			this.removeEventListener(Event.ENTER_FRAME, onStatusEnter );
			dispatchEvent( new VideoStatusEvent( VideoStatusEvent.VIDEO_STOP, url, volume ) );
			
			this.ns.close();
			this.nc.close();
		}
		
		/** 소리 끄기 설정 **/
		public function volumeOff():void
		{
			if( connectionCheck() == false ) return;
			
			_isMute = true;
			_soundTrans.volume = 0;
			this.ns.soundTransform = _soundTrans;
			dispatchEvent( new VideoStatusEvent( VideoStatusEvent.VIDEO_VOLUME_OFF, url, volume ) );
		}
		
		/** 소리 켜기 설정 **/
		public function volumeOn():void
		{
			if( connectionCheck() == false ) return;
			
			_isMute = false;
			_soundTrans.volume = 1;
			this.ns.soundTransform = _soundTrans;
			dispatchEvent( new VideoStatusEvent( VideoStatusEvent.VIDEO_VOLUME_ON, url, volume ) );
		}
		
		/** 비디오 탐색 **/
		public function seek( per:Number ):void
		{
			if( connectionCheck() == false ) return;

			var time : Number = MathUtil.RateToNumber( duraion, 0, per );
			this.ns.seek( time );
		}
		

		
		
		
		
		
		//-----------------------------------------------------------------------------------
		//
		// set api
		//
		//-----------------------------------------------------------------------------------
		
		/** 0~1 의 볼륨값 **/
		public function set volume( __volume:Number ):void
		{
			_volume = __volume;
			_soundTrans.volume = __volume;
			
			if( _isMute ) this.ns.soundTransform.volume = 0;
			else
			{
				if( connectionCheck() == false ) return;
				
				this.ns.soundTransform = _soundTrans;
				dispatchEvent( new VideoStatusEvent( VideoStatusEvent.VIDEO_VOLUME_CHANGE, url, volume ) );
			}
		}
		
		
		/** 0~1 의 볼륨값 반환 **/
		public function get volume():Number
		{
			return _soundTrans.volume;
		}
		
		
		/** 버퍼링 타임 **/		
		public function get bufferTime():int 
		{
			if( this._bufferTime == -1 ) this._bufferTime = 0;
			
			return _bufferTime;
		}
		
		
		/** 몇 초를 기준으로 버퍼링을 줄 것인가. **/
		public function set bufferTime(time:int):void 
		{
			this._bufferTime = time;
			
			if( ns ) ns.bufferTime = _bufferTime;
		}
		
		/** flv 전체 길이 **/
		public function get duraion():Number
		{
			return _duration;
		}
		
		public function get status():String
		{
			return _status;
		}
		
	}
	
}